摘要
Day 8 我們加上了刪除前的確認視窗,避免誤刪。
今天再進一步:刪除後,允許使用者「復原」上一次刪除的資料(Undo)。
刪除時把「被刪的物件」暫存到 deletedStack:多筆堆疊(Stack)Undo。
使用者按「回復上一筆」→ 跳出 confirm → 按確認就把上一筆放回 LocalStorage 並重繪。
deletedStack 只在記憶體,不在 LocalStorage,換分頁或重整會消失。
HTML:
<!-- 回復按鈕 -->
<button id="undoBtn" disabled>回復上一筆</button>
JavaScript:
假設已存在 STORAGE_KEY、readRecords()、writeRecords()(Day 5/6 的函式)。
// ===== 狀態 =====
let deletedStack = []; // 可暫存多筆已刪除資料
const undoBtn = document.getElementById('undoBtn');
// ===== 渲染(新到舊),每筆帶 data-id =====
function renderHistory() {
const el = document.getElementById('historyList');
const records = readRecords().slice().sort((a,b) => b.createdAt - a.createdAt);
el.innerHTML = records.length
? records.map(r => `
<li>
[${new Date(r.createdAt).toLocaleString()}] ${r.task} — ${r.reason} |「${r.quote}」
<button class="btn-delete" data-id="${r.id}">刪除</button>
</li>
`).join('')
: '<li class="muted">尚無紀錄</li>';
// stack 有東西才啟用回復按鈕
undoBtn.disabled = deletedStack.length === 0;
}
// ===== 刪除(依 id;不可變性)=====
function deleteRecordById(id) {
const list = readRecords();
const idx = list.findIndex(r => r.id === id);
if (idx === -1) return false; // 可能被其他分頁刪除,從 Day 8 布林值換為索引值,方便調整資料
const deleted = list[idx];
deletedStack.push(deleted); // 多筆暫存:推入堆疊
const next = list.filter(r => r.id !== id);
writeRecords(next);
return true;
}
// ===== 事件委派:在 <ul> 監聽刪除按鈕點擊 =====
document.getElementById('historyList').addEventListener('click', (e) => {
const btn = e.target.closest('button.btn-delete');
if (!btn) return;
const id = btn.dataset.id;
// Day 9:不再使用 Day 8 的 confirm(本日重點在 Undo)
const ok = deleteRecordById(id);
if (!ok) {
alert('找不到這筆紀錄,可能已被移除或在其他分頁修改。');
return renderHistory();
}
renderHistory(); // 立刻刷新
});
// ===== 回復上一筆(回復最後刪除的那筆)=====
undoBtn.addEventListener('click', () => {
if (deletedStack.length === 0) return; // 保險
const peek = deletedStack[deletedStack.length - 1]; // 看一下即將回復的那筆
const sure = window.confirm(`要回復上一筆刪除嗎?(${peek.task} — ${peek.reason})`);
if (!sure) return;
const rec = deletedStack.pop(); // 真的取出並從堆疊移除,避免重複回復
const list = readRecords();
list.push(rec); // 基礎版:直接 push 回去(若要回原位置可記錄 index 並 splice 插回)
writeRecords(list);
renderHistory();
});
// ===== 多分頁同步 =====
window.addEventListener('storage', (e) => {
if (e.key === STORAGE_KEY) renderHistory();
});
// 保留 Day 8 清空記錄功能:
document.getElementById('clearBtn').addEventListener('click', () => {
if (!window.confirm('確定要清空所有紀錄嗎?清空後無法回復')) return;
localStorage.removeItem(STORAGE_KEY);
renderHistory();
});
// ===== 初次載入 =====
renderHistory();
新增 2 筆資料。
刪除 1 筆 → 「回復上一筆」按鈕變成可用。
再將另一筆刪除 → 按「回復上一筆」→ 跳出 confirm → 按「確定」:該筆回到清單。
再按「回復上一筆」→ 按「確定」:回復上上筆刪除的資料。